#pragma once

#include "comm/my_rbtree.h"
#include "comm/my_spin_lock.h"
#include "event/my_event.h"
#include "cache/util/my_cache_req.h"

typedef struct my_disk_key_lock_tab_s my_disk_key_lock_tab_t;

typedef struct my_disk_key_lock_node_s my_disk_key_lock_node_t;

typedef void(*my_disk_key_lock_done_cb)(my_disk_key_lock_node_t *key_lock_node);

// fusion cache implements singleflight function
// so there will only be one reader at same time.
struct my_disk_key_lock_node_s {
    my_rbtree_node_t            tree_node;
    my_disk_key_lock_tab_t      *lock_tab;  // refer lock_tab
    my_cache_req_t              *req;
    my_disk_key_lock_done_cb    done_cb;
    void                        *ctx_data;  // disk_volume
    my_event_t                  event;      // for retry lock
    int64_t                     retry_counter;
};

static inline void
my_disk_key_lock_node_init(my_disk_key_lock_node_t *node,
    my_disk_key_lock_tab_t *lock_tab, my_cache_req_t *req,
    my_disk_key_lock_done_cb done_cb, void *ctx_data) {

    bzero(node, sizeof(my_disk_key_lock_node_t));
    node->lock_tab = lock_tab;
    node->req = req;
    node->done_cb = done_cb;
    node->ctx_data = ctx_data;
}

struct my_disk_key_lock_tab_s {
    my_spin_lock_t                  spin_lock;
    my_rbtree_t                     rbtree;
    my_rbtree_node_t                sentinel;
};

void
my_disk_key_lock_tab_init(my_disk_key_lock_tab_t *lock_tab);

void
my_disk_key_lock_lock(my_disk_key_lock_node_t *lock_node);

void
my_disk_key_lock_unlock(my_disk_key_lock_node_t *lock_node);